package com.wave.system.task;

import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.wave.common.core.domain.BaseEntity;
import com.wave.common.enums.DeviceNameEnum;
import com.wave.common.utils.DateUtils;
import com.wave.system.domain.SysDeviceSetting;
import com.wave.system.domain.SysDeviceStatus;
import com.wave.system.domain.SysProduceRecord;
import com.wave.system.domain.SysSetting;
import com.wave.system.mapper.SysDeviceSettingMapper;
import com.wave.system.mapper.SysDeviceStatusMapper;
import com.wave.system.mapper.SysProduceRecordMapper;
import com.wave.system.mapper.SysSettingMapper;
import com.wave.system.util.Modbus4jUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Component
@Slf4j
@EnableScheduling
public class BydWcsSysTask {

    @Autowired
    public SysDeviceSettingMapper deviceSettingMapper;

    @Autowired
    public SysDeviceStatusMapper deviceStatusMapper;

    @Autowired
    public SysSettingMapper sysSettingMapper;

    @Autowired
    public SysProduceRecordMapper sysProduceRecordMapper;

    @Autowired
    public ThreadPoolExecutor threadPoolExecutor;


    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(10);
        return taskScheduler;
    }

    @Scheduled(cron = "0/2 * * * * ?")
    public void wcsHearBeatTask() {
        try {
            Modbus4jUtils.writeCoil(1, 4104, true);
        } catch (Exception e) {
            log.error("上位机心跳定时任务异常", e);
        }
    }

    @Scheduled(cron = "0 0 0 * * ?")
    public void autoClearProduceRecord() {
        SysSetting sysSetting = sysSettingMapper.selectOne(Wrappers.emptyWrapper());
        if (ObjectUtil.isEmpty(sysSetting)) {
            log.error("未配置系统设置");
            return;
        }
        Integer cleanSetting = sysSetting.getCleanSetting();
        if (cleanSetting == 1) {
            return;
        }
        Integer cleanHistoryMonth = sysSetting.getCleanHistoryMonth();
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime localDateTime = now.minusMonths(cleanHistoryMonth);
        Date date = DateUtils.toDate(localDateTime);
        while (true) {
            LambdaQueryWrapper<SysProduceRecord> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.le(BaseEntity::getCreateTime, date).last("limit 1000");
            List<SysProduceRecord> sysProduceRecords = sysProduceRecordMapper.selectList(queryWrapper);
            if (CollectionUtils.isEmpty(sysProduceRecords)) {
                log.info("没有要清理的数据");
                return;
            }
            List<Long> idList = sysProduceRecords.stream().map(SysProduceRecord::getId).collect(Collectors.toList());
            sysProduceRecordMapper.deleteBatchIds(idList);
            if (idList.size() < 1000) {
                break;
            }
        }
    }


    /**
     * 维护设备状态
     */
    @Scheduled(cron = "0 0/2 * * * ? ")
    public void updateDeviceStatus() {
        SysDeviceSetting sysDeviceSetting = deviceSettingMapper.selectOne(Wrappers.emptyWrapper());
        if (ObjectUtil.isEmpty(sysDeviceSetting)) {
            log.error("未配置设备信息");
            return;
        }
        String ip = "";
        for (DeviceNameEnum value : DeviceNameEnum.values()) {
            if (DeviceNameEnum.PLC.equals(value)) {
                ip = sysDeviceSetting.getMcsPlcIp();
            } else if (DeviceNameEnum.QR_CODE_READER1.equals(value)) {
                ip = sysDeviceSetting.getToolBoardIp();
            } else if (DeviceNameEnum.PACKAGE_LINE1_RFID_READER1.equals(value)) {
                ip = sysDeviceSetting.getPackagingLine1Ip();
            } else if (DeviceNameEnum.PACKAGE_LINE1_RFID_READER2.equals(value)) {
                ip = sysDeviceSetting.getPackagingLine1Ip2();
            } else if (DeviceNameEnum.PACKAGE_LINE2_RFID_READER1.equals(value)) {
                ip = sysDeviceSetting.getPackagingLine2Ip();
            } else if (DeviceNameEnum.PACKAGE_LINE2_RFID_READER2.equals(value)) {
                ip = sysDeviceSetting.getPackagingLine2Ip2();
            } else if (DeviceNameEnum.PACKAGE_LINE3_RFID_READER1.equals(value)) {
                ip = sysDeviceSetting.getPackagingLine3Ip();
            } else if (DeviceNameEnum.PACKAGE_LINE3_RFID_READER2.equals(value)) {
                ip = sysDeviceSetting.getPackagingLine3Ip2();
            } else if (DeviceNameEnum.PACKAGE_LINE4_RFID_READER1.equals(value)) {
                ip = sysDeviceSetting.getPackagingLine4Ip();
            } else if (DeviceNameEnum.PACKAGE_LINE4_RFID_READER2.equals(value)) {
                ip = sysDeviceSetting.getPackagingLine4Ip2();
            }else {
                continue;
            }
            boolean success = NetUtil.ping(ip, 3000);
            Integer deviceStatus = success ? 0 : 1;
            LambdaQueryWrapper<SysDeviceStatus> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysDeviceStatus::getDeviceName, value.getDeviceName());
            SysDeviceStatus sysDeviceStatus = deviceStatusMapper.selectOne(queryWrapper);
            if (ObjectUtil.isNotEmpty(sysDeviceStatus) && sysDeviceStatus.getDeviceStatus().equals(deviceStatus)) {
                continue;
            }
            String abnormalCause = success ? "" : "离线";
            LambdaUpdateWrapper<SysDeviceStatus> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(SysDeviceStatus::getDeviceStatus, deviceStatus);
            updateWrapper.set(SysDeviceStatus::getAbnormalCause, abnormalCause);
            updateWrapper.set(SysDeviceStatus::getUpdateTime, new Date());
            updateWrapper.eq(SysDeviceStatus::getDeviceName, value.getDeviceName());
            deviceStatusMapper.update(updateWrapper);
        }
    }
}
